package com.icbc.dccsh.storm.mongodb.common;

import java.util.List;

import org.bson.Document;
import org.bson.conversions.Bson;

import com.mongodb.MongoClient;
import com.mongodb.MongoClientURI;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.model.InsertManyOptions;
import com.mongodb.client.model.UpdateOptions;

public class MongoDBClient {
	private MongoClient _client;
	private MongoDatabase _db;
	private String _lastCollectionName = "_not_initialized_";
	private MongoCollection<Document> _collection;

	public MongoDBClient(String url) {
		MongoClientURI uri = new MongoClientURI(url);
		// Creates a MongoClient described by a URI.
		this._client = new MongoClient(uri);
		// Gets a Database.
		this._db = _client.getDatabase(uri.getDatabase());
	}

	public MongoDBClient(String url, String collectionName) {
		this(url);
		// // Creates a MongoURI from the given string.
		// MongoClientURI uri = new MongoClientURI(url);
		// // Creates a MongoClient described by a URI.
		// this._client = new MongoClient(uri);
		// // Gets a Database.
		// this._db = _client.getDatabase(uri.getDatabase());
		// // Gets a collection.
		this._collection = this.getCollection(collectionName);
		// this._collection = this._db.getCollection(collectionName);
	}

	private MongoCollection<Document> getCollection(String collectionName) {
		if (!this._lastCollectionName.equals(collectionName)) {
			this._collection = this._db.getCollection(collectionName);
			this._lastCollectionName = collectionName;
		}
		return this._collection;
	}

	private void insert(MongoCollection<Document> collection, List<Document> documents, boolean ordered) {
		InsertManyOptions options = new InsertManyOptions();
		if (!ordered) {
			options.ordered(false);
		}
		collection.insertMany(documents, options);
	}

	public void insert(String collectionName, List<Document> documents, boolean ordered) {
		// this._collection = _db.getCollection(collectionName);
		this._collection = this.getCollection(collectionName);
		this.insert(this._collection, documents, ordered);
	}

	/**
	 * Inserts one or more documents. This method is equivalent to a call to the
	 * bulkWrite method. The documents will be inserted in the order provided,
	 * stopping on the first failed insertion.
	 * 
	 * @param documents
	 */
	public void insert(List<Document> documents, boolean ordered) {
		insert(this._collection, documents, ordered);
		// InsertManyOptions options = new InsertManyOptions();
		// if (!ordered) {
		// options.ordered(false);
		// }
		// _collection.insertMany(documents, options);
	}

	/**
	 * Update all documents in the collection according to the specified query
	 * filter. When upsert set to true, the new document will be inserted if
	 * there are no matches to the query filter.
	 * 
	 * @param filter
	 * @param update
	 * @param upsert
	 */
	public void update(Bson filter, Bson update, boolean upsert) {
		UpdateOptions options = new UpdateOptions();
		if (upsert) {
			options.upsert(true);
		}
		_collection.updateMany(filter, update, options);
	}

	/**
	 * Closes all resources associated with this instance.
	 */
	public void close() {
		_client.close();
	}
}
